1 package org.apache.maven.surefire.junitcore.pc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.junit.runner.Description;
23 import org.junit.runners.model.RunnerScheduler;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Set;
28 import java.util.concurrent.CopyOnWriteArraySet;
29 import java.util.concurrent.RejectedExecutionException;
30 import java.util.concurrent.RejectedExecutionHandler;
31 import java.util.concurrent.ThreadPoolExecutor;
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class Scheduler
46 implements RunnerScheduler
47 {
48 private final Balancer balancer;
49
50 private final SchedulingStrategy strategy;
51
52 private final Set<Controller> slaves = new CopyOnWriteArraySet<Controller>();
53
54 private final Description description;
55
56 private volatile boolean shutdown = false;
57
58 private volatile boolean started = false;
59
60 private volatile Controller masterController;
61
62
63
64
65
66
67
68 public Scheduler( Description description, SchedulingStrategy strategy )
69 {
70 this( description, strategy, -1 );
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public Scheduler( Description description, SchedulingStrategy strategy, int concurrency )
86 {
87 this( description, strategy, BalancerFactory.createBalancer( concurrency ) );
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 public Scheduler( Description description, SchedulingStrategy strategy, Balancer balancer )
104 {
105 strategy.setDefaultShutdownHandler( newShutdownHandler() );
106 this.description = description;
107 this.strategy = strategy;
108 this.balancer = balancer;
109 masterController = null;
110 }
111
112
113
114
115
116
117
118
119
120
121
122 public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy,
123 Balancer balancer )
124 {
125 this( description, strategy, balancer );
126 strategy.setDefaultShutdownHandler( newShutdownHandler() );
127 masterScheduler.register( this );
128 }
129
130
131
132
133
134
135
136 public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy, int concurrency )
137 {
138 this( description, strategy, concurrency );
139 strategy.setDefaultShutdownHandler( newShutdownHandler() );
140 masterScheduler.register( this );
141 }
142
143
144
145
146
147
148
149 public Scheduler( Description description, Scheduler masterScheduler, SchedulingStrategy strategy )
150 {
151 this( description, masterScheduler, strategy, 0 );
152 }
153
154 private void setController( Controller masterController )
155 {
156 if ( masterController == null )
157 {
158 throw new NullPointerException( "null ExecutionController" );
159 }
160 this.masterController = masterController;
161 }
162
163
164
165
166
167 private boolean register( Scheduler slave )
168 {
169 boolean canRegister = slave != null && slave != this;
170 if ( canRegister )
171 {
172 Controller controller = new Controller( slave );
173 canRegister = !slaves.contains( controller );
174 if ( canRegister )
175 {
176 slaves.add( controller );
177 slave.setController( controller );
178 }
179 }
180 return canRegister;
181 }
182
183
184
185
186 private boolean canSchedule()
187 {
188 return !shutdown && ( masterController == null || masterController.canSchedule() );
189 }
190
191 protected void logQuietly( Throwable t )
192 {
193 t.printStackTrace( System.err );
194 }
195
196 protected void logQuietly( String msg )
197 {
198 System.err.println( msg );
199 }
200
201
202
203
204
205
206
207
208
209
210
211 public Collection<Description> shutdown( boolean shutdownNow )
212 {
213 shutdown = true;
214 ArrayList<Description> activeChildren = new ArrayList<Description>();
215
216 if ( started && description != null )
217 {
218 activeChildren.add( description );
219 }
220
221 for ( Controller slave : slaves )
222 {
223 try
224 {
225 activeChildren.addAll( slave.shutdown( shutdownNow ) );
226 }
227 catch ( Throwable t )
228 {
229 logQuietly( t );
230 }
231 }
232
233 try
234 {
235 balancer.releaseAllPermits();
236 }
237 finally
238 {
239 if ( shutdownNow )
240 {
241 strategy.stopNow();
242 }
243 else
244 {
245 strategy.stop();
246 }
247 }
248
249 return activeChildren;
250 }
251
252 protected void beforeExecute()
253 {
254 }
255
256 protected void afterExecute()
257 {
258 }
259
260 public void schedule( Runnable childStatement )
261 {
262 if ( childStatement == null )
263 {
264 logQuietly( "cannot schedule null" );
265 }
266 else if ( canSchedule() && strategy.canSchedule() )
267 {
268 try
269 {
270 boolean isNotInterrupted = balancer.acquirePermit();
271 if ( isNotInterrupted && !shutdown )
272 {
273 Runnable task = wrapTask( childStatement );
274 strategy.schedule( task );
275 started = true;
276 }
277 }
278 catch ( RejectedExecutionException e )
279 {
280 shutdown( false );
281 }
282 catch ( Throwable t )
283 {
284 balancer.releasePermit();
285 logQuietly( t );
286 }
287 }
288 }
289
290 public void finished()
291 {
292 try
293 {
294 strategy.finished();
295 }
296 catch ( InterruptedException e )
297 {
298 logQuietly( e );
299 }
300 finally
301 {
302 for ( Controller slave : slaves )
303 {
304 slave.awaitFinishedQuietly();
305 }
306 }
307 }
308
309 private Runnable wrapTask( final Runnable task )
310 {
311 return new Runnable()
312 {
313 public void run()
314 {
315 try
316 {
317 beforeExecute();
318 task.run();
319 }
320 finally
321 {
322 try
323 {
324 afterExecute();
325 }
326 finally
327 {
328 balancer.releasePermit();
329 }
330 }
331 }
332 };
333 }
334
335 protected ShutdownHandler newShutdownHandler()
336 {
337 return new ShutdownHandler();
338 }
339
340
341
342
343 private final class Controller
344 {
345 private final Scheduler slave;
346
347 private Controller( Scheduler slave )
348 {
349 this.slave = slave;
350 }
351
352
353
354
355 boolean canSchedule()
356 {
357 return Scheduler.this.canSchedule();
358 }
359
360 void awaitFinishedQuietly()
361 {
362 try
363 {
364 slave.finished();
365 }
366 catch ( Throwable t )
367 {
368 slave.logQuietly( t );
369 }
370 }
371
372 Collection<Description> shutdown( boolean shutdownNow )
373 {
374 return slave.shutdown( shutdownNow );
375 }
376
377 @Override
378 public int hashCode()
379 {
380 return slave.hashCode();
381 }
382
383 @Override
384 public boolean equals( Object o )
385 {
386 return o == this || ( o instanceof Controller ) && slave.equals( ( (Controller) o ).slave );
387 }
388 }
389
390 public class ShutdownHandler
391 implements RejectedExecutionHandler
392 {
393 private volatile RejectedExecutionHandler poolHandler;
394
395 protected ShutdownHandler()
396 {
397 poolHandler = null;
398 }
399
400 public void setRejectedExecutionHandler( RejectedExecutionHandler poolHandler )
401 {
402 this.poolHandler = poolHandler;
403 }
404
405 public void rejectedExecution( Runnable r, ThreadPoolExecutor executor )
406 {
407 if ( executor.isShutdown() )
408 {
409 shutdown( false );
410 }
411 final RejectedExecutionHandler poolHandler = this.poolHandler;
412 if ( poolHandler != null )
413 {
414 poolHandler.rejectedExecution( r, executor );
415 }
416 }
417 }
418 }